<?php
namespace core\db;

use core\db\Model;

/**
 * 模型关联Trait
 * 提供一对一、一对多和多对多关联功能
 */
trait Relation {
    /**
     * 一对一关联
     * @param string $relatedModel 关联模型类名
     * @param string $foreignKey 外键字段
     * @param string $localKey 本地键字段
     * @return mixed
     */
    public function hasOne($relatedModel, $foreignKey = null, $localKey = null) {
        $foreignKey = $foreignKey ?: static::getForeignKey();
        $localKey = $localKey ?: static::getPrimaryKey();
        $localValue = $this->{$localKey};
    
        return $relatedModel::findAll([$foreignKey => $localValue], '', 1)[0] ?? null;
    }

    /**
     * 一对多关联
     * @param string $relatedModel 关联模型类名
     * @param string $foreignKey 外键字段
     * @param string $localKey 本地键字段
     * @return array
     */
    public function hasMany($relatedModel, $foreignKey = null, $localKey = null) {
        $foreignKey = $foreignKey ?: static::getForeignKey();
        $localKey = $localKey ?: static::getPrimaryKey();
        $localValue = $this->{$localKey};
    
        return $relatedModel::findAll([$foreignKey => $localValue]);
    }

    /**
     * 多对多关联
     * @param string $relatedModel 关联模型类名
     * @param string $pivotTable 中间表名
     * @param string $foreignKey 外键字段
     * @param string $relatedKey 关联键字段
     * @return array
     */
    public function belongsToMany($relatedModel, $pivotTable, $foreignKey = null, $relatedKey = null) {
        $foreignKey = $foreignKey ?: static::getForeignKey();
        $relatedKey = $relatedKey ?: (new $relatedModel())->getForeignKey();
        $localKey = static::getPrimaryKey();
        $localValue = $this->{$localKey};
    
        // 获取关联模型的表名
        $relatedTable = $relatedModel::getTableName();
        $relatedPrimaryKey = $relatedModel::getPrimaryKey();
    
        // 构建SQL查询
        $sql = "SELECT {$relatedTable}.* FROM {$relatedTable}"
             . " JOIN {$pivotTable} ON {$relatedTable}.{$relatedPrimaryKey} = {$pivotTable}.{$relatedKey}"
             . " WHERE {$pivotTable}.{$foreignKey} = ?";
    
        // 执行查询
        $db = Database::getInstance()->getConnection();
        $stmt = $db->prepare($sql);
        $stmt->execute([$localValue]);
        return $stmt->fetchAll();
    }

    /**
     * 属于关联（多对一）
     * @param string $relatedModel 关联模型类名
     * @param string $foreignKey 外键字段
     * @param string $ownerKey 关联模型的主键
     * @return mixed
     */
    public function belongsTo($relatedModel, $foreignKey = null, $ownerKey = null) {
        $foreignKey = $foreignKey ?: (new $relatedModel())->getForeignKey();
        $ownerKey = $ownerKey ?: $relatedModel::getPrimaryKey();
    
        if (!isset($this->{$foreignKey})) {
            return null;
        }
    
        return $relatedModel::find($this->{$foreignKey});
    }

    /**
     * 获取外键名称
     * @return string 外键字段名
     */
    protected static function getForeignKey() {
        // 默认外键规则: 模型类名小写 + _id
        // 获取当前模型类名
        $className = static::class;
        // 获取类名的最后一部分
        $shortName = substr(strrchr($className, '\\'), 1);
        // 转为小写并添加_id后缀
        return strtolower($shortName) . '_id';
    }
}